#include "rsa.h"


Rsa::Rsa(const std::string& publicKeyFile, const std::string& privateKeyFile)
{
	_publicKeyFile = publicKeyFile;
	_privateKeyFile = privateKeyFile;
}

Rsa::~Rsa()
{

}

bool Rsa::encrypt(const std::string& in, std::string& out, const bool usePublicKey)
{
	return this->crypt(in, out, true, usePublicKey);
}

bool Rsa::decrypt(const std::string& in, std::string& out, const bool usePublicKey)
{
	return this->crypt(in, out, false, usePublicKey);
}

bool Rsa::crypt(const std::string& in, std::string& out, const bool encrypt, const bool usePublicKey)
{
	std::string& fileName = usePublicKey ? _publicKeyFile : _privateKeyFile;
    FILE* keyFile = fopen(fileName.c_str(), "rb");  
    if( keyFile == NULL )  
    {  
        return false;   
    }  

    std::string strRet;  
    RSA* rsaKey = RSA_new(); 
	RSA *pRsa;
	if(usePublicKey)
	{
		pRsa = PEM_read_RSA_PUBKEY(keyFile, &rsaKey, 0, 0);
	}
	else 
	{
		pRsa = PEM_read_RSAPrivateKey(keyFile, &rsaKey, 0, 0);
	}

	if(pRsa == NULL)
	{
		return false;
	}
    
	int nLen = RSA_size(rsaKey);  
    char* pOut = new char[nLen + 1];  
	unsigned char *pIn = new unsigned char[nLen + 1];
	memset(pIn, 0, nLen + 1);
	memcpy(pIn, in.c_str(), in.size());
	int ret;
	if(encrypt)
	{
		if(usePublicKey)
		{
    		ret = RSA_public_encrypt(nLen, pIn, (unsigned char*)pOut, rsaKey, RSA_NO_PADDING);  
    	}
		else 
		{
    		ret = RSA_private_encrypt(nLen, pIn, (unsigned char*)pOut, rsaKey, RSA_NO_PADDING);  
		}
	}
	else 
	{
		if(usePublicKey)
		{
    		ret = RSA_public_decrypt(nLen, pIn, (unsigned char*)pOut, rsaKey, RSA_NO_PADDING);  
    	}
		else 
		{
    		ret = RSA_private_decrypt(nLen, pIn, (unsigned char*)pOut, rsaKey, RSA_NO_PADDING);  
		}
	}

	if (ret >= 0)  
    {  
        out = std::string(pOut, ret);  
    }
  
	delete[] pIn;
    delete[] pOut;  
    RSA_free(rsaKey);  
    fclose(keyFile);  
    CRYPTO_cleanup_all_ex_data();   
    return ret >= 0 ? true : false;  
}

